/*
 *    Copyright 2009-2010 The iBaGuice Team
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package com.google.code.ibaguice.samples;

import java.io.File;
import java.io.StringReader;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import lombok.Setter;

import org.apache.ibatis.jdbc.ScriptRunner;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.google.code.ibaguice.core.SqlSessionFactoryModule;
import com.google.code.ibaguice.core.datasource.PooledDataSourceProvider;
import com.google.code.ibaguice.dao.TransactionalModule;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.name.Names;

/**
 * 
 *
 * @author Simone Tripodi
 * @version $Id: AbstractTestCase.java 1218 2010-01-25 08:38:08Z simone.tripodi $
 */
public abstract class AbstractTestCase {

    @Inject
    @Setter
    private ContactDao contactDao;

    private final Contact contact = new Contact();

    protected Contact getContact() {
        return this.contact;
    }

    @BeforeClass
    public void setUp() throws Exception {
        this.contact.setFirstName("Simone");
        this.contact.setLastName("Tripodi");

        // db URL setup
        File tmp = File.createTempFile("dbTEST", ".dat");
        tmp.delete();
        final String connectionURL = "jdbc:derby:"
            + tmp.getAbsolutePath()
            + ";create=true";

        final Properties ibatisProperties = new Properties();
        ibatisProperties.setProperty("ibatis.environment.id", "test");
        ibatisProperties.setProperty("JDBC.driver", "org.apache.derby.jdbc.EmbeddedDriver");
        ibatisProperties.setProperty("JDBC.url", connectionURL);
        ibatisProperties.setProperty("JDBC.username", "");
        ibatisProperties.setProperty("JDBC.password", "");
        ibatisProperties.setProperty("JDBC.autoCommit", "true");

        // bindings
        SqlSessionFactoryModule ibatisModule = new SqlSessionFactoryModule(this.getDataSourceProviderClass());

        ibatisModule.addSimpleAliases(Contact.class);
        ibatisModule.setMapperClasses(getMapperClass());

        Injector injector = Guice.createInjector(ibatisModule,
                new TransactionalModule(),
                new Module() {
                    public void configure(Binder binder) {
                        binder.bind(ContactDao.class).to(getDaoClass()).asEagerSingleton();
                        Names.bindProperties(binder, ibatisProperties);
                        addAuxBinds(binder);
                    }
                });

        // prepare the test db
        DataSource dataSource = injector.getInstance(DataSource.class);
        ScriptRunner runner = new ScriptRunner(dataSource.getConnection());
        runner.setAutoCommit(true);
        runner.setStopOnError(true);
        runner.runScript(new StringReader(
                "CREATE TABLE contact (id INT NOT NULL PRIMARY KEY GENERATED "
                + "ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), first_name "
                + "VARCHAR(20) NOT NULL, last_name VARCHAR(20) NOT NULL);"));
        runner.closeConnection();

        injector.injectMembers(this);
    }

    @Test
    public void insertContact() throws Exception {
        this.contactDao.insert(this.getContact());
    }

    @Test(dependsOnMethods = { "insertContact" })
    public void selectAllContacts() throws Exception {
        List<Contact> contacts = this.contactDao.getAll();
        assert contacts.size() > 0 : "Expected not empty contact table";
    }

    @Test(dependsOnMethods = "selectAllContacts")
    public void reSelectAllContacts() throws Exception {
        List<Contact> contacts = this.contactDao.getAll();
        assert contacts.size() > 0 : "Expected not empty contact table";
    }

    @Test(dependsOnMethods = "insertContact")
    public void selectContact() throws Exception {
        Contact contact = this.contactDao.selectById(this.getContact().getId());
        assert contact != null : "impossible to retrieve Contact with id '"
                                + this.getContact().getId()
                                + "'";
        assert this.getContact().equals(contact) : "Expected "
                                                + this.getContact()
                                                + " but found "
                                                + contact;
    }

    @Test
    public void catchSQLException() throws Exception {
        Contact contact = this.contactDao.selectById(this.getContact().getId());
        assert contact != null : "impossible to retrieve Contact with id '"
                                + this.getContact().getId()
                                + "'";
        assert this.getContact().equals(contact) : "Expected "
                                                + this.getContact()
                                                + " but found "
                                                + contact;
    }

    protected abstract Class<?>[]  getMapperClass();

    protected abstract Class<? extends ContactDao> getDaoClass();

    protected Class<? extends Provider<DataSource>> getDataSourceProviderClass() {
        return PooledDataSourceProvider.class;
    }

    protected void addAuxBinds(Binder binder) {
        // do nothing
    }

}
